// ball_streamobserver.h                                              -*-C++-*-
#ifndef INCLUDED_BALL_STREAMOBSERVER
#define INCLUDED_BALL_STREAMOBSERVER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an observer that emits log records to a stream.
//
//@CLASSES:
//  ball::StreamObserver: observer that emits log records to a stream
//
//@SEE_ALSO: ball_record, ball_context, ball_loggermanager
//
//@DESCRIPTION: This component provides a concrete implementation of the
// `ball::Observer` protocol for receiving and processing log records:
// ```
//                ,--------------------.
//               ( ball::StreamObserver )
//                `--------------------'
//                          |              ctor
//                          |              setRecordFormatFunctor
//                          V
//                   ,--------------.
//                  ( ball::Observer )
//                   `--------------'
//                                         publish
//                                         releaseRecords
//                                         dtor
// ```
// `ball::StreamObserver` is a concrete class derived from `ball::Observer`
// that processes the log records it receives through its `publish` method by
// writing them to an output stream.  Given its minimal functionality,
// `ball::StreamObserver` should be used with care in a production environment.
// It is not recommended to construct this observer with file-based streams due
// to lack of any file rotation functionality.
//
///Log Record Formatting
///---------------------
// By default, the output format of published log records is:
// ```
// DATE_TIME PID THREAD-ID SEVERITY FILE LINE CATEGORY MESSAGE USER-FIELDS
// ```
// where `DATE` and `TIME` are of the form `DDMonYYYY` and `HH:MM:SS.mmm`,
// respectively (`Mon` being the 3-letter abbreviation for the month).  For
// example, assuming that no user-defined fields are present, a log record
// will have the following appearance when the default format is in effect:
// ```
// 18MAY2005_18:58:12.076 7959 1 WARN ball_streamobserver2.t.cpp 404 TEST hi!
// ```
// The default format can be overridden by supplying a suitable formatting
// functor to `setRecordFormatFunctor`.  For example, an instance of
// `ball::RecordStringFormatter` conveniently provides such a functor:
// ```
// streamObserver.setRecordFormatFunctor(
//             ball::RecordStringFormatter("\n%I %p:%t %s %f:%l %c %m %u\n"));
// ```
// The above statement will cause subsequent records to be logged in a format
// that is almost identical to the default format except that the timestamp
// attribute will be written in ISO 8601 format.  See
// {`ball_recordstringformatter`} for information on how format specifications
// are defined and interpreted.
//
// Note that the observer emits newline characters at the beginning and at the
// end of a log record by default, so the user needs to add them explicitly to
// the format string to preserve this behavior.
//
// Also note that in the sample message above the timestamp has millisecond
// precision (`18MAY2005_18:58:12.076`).  If microsecond precision is desired
// instead, consider using either the `%D` or `%O` format specification
// supported by `ball_recordstringformatter`.
//
///Thread Safety
///-------------
// All methods of `ball::StreamObserver` are thread-safe, and can be called
// concurrently by multiple threads.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Usage
/// - - - - - - - - - - -
// The following snippets of code illustrate the basic usage of
// `ball::StreamObserver`.
//
// First create a `ball::Record` object `record` and a `ball::Context` object
// `context`.  Note that the default values for these objects (or their
// contained objects) are perfectly suitable for logging purposes.
// ```
// ball::RecordAttributes attributes;
// ball::UserFields       fieldValues;
// ball::Context          context;
//
// bslma::Allocator *ga = bslma::Default::globalAllocator(0);
// const bsl::shared_ptr<const ball::Record>
//            record(new (*ga) ball::Record(attributes, fieldValues, ga), ga);
// ```
// Next, create a stream observer `observer` with the `bsl::cout` as the output
// stream.
// ```
// ball::StreamObserver observer(&bsl::cout);
// ```
// Finally, publish `record` and `context` to `observer`.
// ```
// observer.publish(record, context);
// ```
// This will produce the following output on `stdout`:
// ```
// 01JAN0001_24:00:00.000 0 0 OFF  0
// ```

#include <balscm_version.h>

#include <ball_observer.h>

#include <bslma_allocator.h>
#include <bslma_bslallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_nestedtraitdeclaration.h>

#include <bslmt_mutex.h>

#include <bsls_assert.h>
#include <bsls_keyword.h>
#include <bsls_review.h>

#include <bsl_iosfwd.h>
#include <bsl_functional.h>

namespace BloombergLP {
namespace ball {

class Context;
class Record;

                           // ====================
                           // class StreamObserver
                           // ====================

/// This class provides a concrete implementation of the `Observer`
/// protocol.  The `publish` method of this class outputs the log records
/// that it receives to an instance of `bsl::ostream` supplied at
/// construction.
class StreamObserver : public Observer {

  public:
    // TYPES

    /// `RecordFormatFunctor` is an alias for the type of the functor used
    /// for formatting log records to a stream.
    typedef bsl::function<void(bsl::ostream&, const Record&)>
                                                           RecordFormatFunctor;

    typedef bsl::allocator<char> allocator_type;

  private:
    // DATA
    bsl::ostream        *d_stream_p;   // output sink for log records

    bslmt::Mutex         d_mutex;      // serializes concurrent calls to
                                       // 'publish'

    RecordFormatFunctor  d_formatter;  // formatting functor used when writing
                                       // to log file

    // NOT IMPLEMENTED
    StreamObserver(const StreamObserver&);
    StreamObserver& operator=(const StreamObserver&);

    // CLASS METHODS

    /// Write the specified log `record` to the specified output `stream`
    /// using the default record format of this stream observer.
    static
    void logRecordDefault(bsl::ostream& stream, const Record& record);

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(StreamObserver, bslma::UsesBslmaAllocator);

    // CREATORS

    /// Create a stream observer that transmits log records to the specified
    /// `stream`.  Optionally specify an `allocator` (e.g., the address of a
    /// `bslma::Allocator` object) to supply memory; otherwise, the default
    /// allocator is used.  Note that a default record format is in effect
    /// for stream logging (see `setLogFileFunctor`).
    explicit
    StreamObserver(bsl::ostream          *stream,
                   const allocator_type&  allocator = allocator_type());

    /// Destroy this stream observer.
    ~StreamObserver() BSLS_KEYWORD_OVERRIDE;

    // MANIPULATORS
    using Observer::publish;

    /// Process the specified log `record` having the specified publishing
    /// `context`.  Print `record` and `context` to the `bsl::ostream`
    /// supplied at construction.  The behavior is undefined if `record` or
    /// `context` is modified during the execution of this method.
    void publish(const bsl::shared_ptr<const Record>& record,
                 const Context&                       context)
                                                         BSLS_KEYWORD_OVERRIDE;

    /// Discard any shared reference to a `Record` object that was supplied
    /// to the `publish` method, and is held by this observer.  Note that
    /// this operation should be called if resources underlying the
    /// previously provided shared-pointers must be released.
    void releaseRecords() BSLS_KEYWORD_OVERRIDE;

    /// Set the formatting functor used when writing records to the log file
    /// of this file observer to the specified `formatter` functor.  Note
    /// that a default format ("\n%d %p %t %s %f %l %c %m %u\n") is in
    /// effect until this method is called (see
    /// `ball_recordstringformatter`).  Also note that the observer emits
    /// newline characters at the beginning and at the end of a log record
    /// by default, so the user needs to add them explicitly to the format
    /// string to preserve this behavior.
    void setRecordFormatFunctor(const RecordFormatFunctor& formatter);
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                           // --------------------
                           // class StreamObserver
                           // --------------------

// MANIPULATORS
inline
void StreamObserver::releaseRecords()
{
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2017 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
